//! # Principal 构建器工具
//!
//! 提供统一的 Principal 创建和转换工具，避免在各个认证提供者中重复实现相同的逻辑。

use crate::auth::types::*;
use std::time::{SystemTime, UNIX_EPOCH, Duration};
use std::collections::HashMap;

/// Principal 构建器
pub struct PrincipalBuilder {
    id: String,
    name: Option<String>,
    principal_type: Option<PrincipalType>,
    roles: Vec<String>,
    permissions: Vec<String>,
    attributes: HashMap<String, String>,
    expires_at: Option<SystemTime>,
}

impl PrincipalBuilder {
    /// 创建新的构建器
    pub fn new(id: String) -> Self {
        Self {
            id,
            name: None,
            principal_type: None,
            roles: Vec::new(),
            permissions: Vec::new(),
            attributes: HashMap::new(),
            expires_at: None,
        }
    }

    /// 设置名称
    pub fn name(mut self, name: String) -> Self {
        self.name = Some(name);
        self
    }

    /// 设置主体类型
    pub fn principal_type(mut self, principal_type: PrincipalType) -> Self {
        self.principal_type = Some(principal_type);
        self
    }

    /// 从字符串设置主体类型
    pub fn principal_type_from_str(mut self, type_str: &str) -> Self {
        let principal_type = match type_str.to_lowercase().as_str() {
            "admin" => PrincipalType::Admin,
            "service" => PrincipalType::Service,
            "system" => PrincipalType::System,
            "anonymous" => PrincipalType::Anonymous,
            custom => PrincipalType::Custom(custom.to_string()),
        };
        self.principal_type = Some(principal_type);
        self
    }

    /// 添加角色
    pub fn role(mut self, role: String) -> Self {
        self.roles.push(role);
        self
    }

    /// 添加多个角色
    pub fn roles<I>(mut self, roles: I) -> Self 
    where
        I: IntoIterator<Item = String>,
    {
        self.roles.extend(roles);
        self
    }

    /// 添加权限
    pub fn permission(mut self, permission: String) -> Self {
        self.permissions.push(permission);
        self
    }

    /// 添加多个权限
    pub fn permissions<I>(mut self, permissions: I) -> Self 
    where
        I: IntoIterator<Item = String>,
    {
        self.permissions.extend(permissions);
        self
    }

    /// 添加属性
    pub fn attribute(mut self, key: String, value: String) -> Self {
        self.attributes.insert(key, value);
        self
    }

    /// 添加多个属性
    pub fn attributes(mut self, attributes: HashMap<String, String>) -> Self {
        self.attributes.extend(attributes);
        self
    }

    /// 设置过期时间
    pub fn expires_at(mut self, expires_at: SystemTime) -> Self {
        self.expires_at = Some(expires_at);
        self
    }

    /// 设置过期时间（从Unix时间戳）
    pub fn expires_at_timestamp(mut self, timestamp: i64) -> Self {
        self.expires_at = Some(UNIX_EPOCH + Duration::from_secs(timestamp as u64));
        self
    }

    /// 设置过期时间（从现在开始的持续时间）
    pub fn expires_after(mut self, duration: Duration) -> Self {
        self.expires_at = Some(SystemTime::now() + duration);
        self
    }

    /// 构建 Principal
    pub fn build(self) -> Principal {
        let name = self.name.unwrap_or_else(|| self.id.clone());
        let principal_type = self.principal_type.unwrap_or(PrincipalType::User);

        let mut principal = Principal::new(self.id, name, principal_type);

        // 添加角色
        for role in self.roles {
            principal = principal.add_role(role);
        }

        // 添加权限
        for permission in self.permissions {
            principal = principal.add_permission(permission);
        }

        // 添加属性
        for (key, value) in self.attributes {
            principal = principal.add_attribute(key, value);
        }

        // 设置过期时间
        if let Some(expires_at) = self.expires_at {
            principal = principal.with_expiry(expires_at);
        }

        principal
    }
}

/// Principal 转换工具
pub struct PrincipalConverter;

impl PrincipalConverter {
    /// 从 JWT Claims 创建 Principal
    pub fn from_jwt_claims(
        user_id: String,
        claims: &HashMap<String, serde_json::Value>,
    ) -> PrincipalBuilder {
        let mut builder = PrincipalBuilder::new(user_id);

        // 提取名称
        if let Some(name) = claims.get("name").and_then(|v| v.as_str()) {
            builder = builder.name(name.to_string());
        }

        // 提取用户类型
        if let Some(user_type) = claims.get("user_type").and_then(|v| v.as_str()) {
            builder = builder.principal_type_from_str(user_type);
        }

        // 提取角色
        if let Some(roles) = claims.get("roles").and_then(|v| v.as_array()) {
            let role_strings: Vec<String> = roles
                .iter()
                .filter_map(|v| v.as_str())
                .map(|s| s.to_string())
                .collect();
            builder = builder.roles(role_strings);
        }

        // 提取权限
        if let Some(permissions) = claims.get("permissions").and_then(|v| v.as_array()) {
            let permission_strings: Vec<String> = permissions
                .iter()
                .filter_map(|v| v.as_str())
                .map(|s| s.to_string())
                .collect();
            builder = builder.permissions(permission_strings);
        }

        // 提取过期时间
        if let Some(exp) = claims.get("exp").and_then(|v| v.as_i64()) {
            builder = builder.expires_at_timestamp(exp);
        }

        // 提取自定义属性
        let reserved_keys = ["name", "user_type", "roles", "permissions", "exp", "iat", "nbf", "sub", "iss", "aud"];
        for (key, value) in claims {
            if !reserved_keys.contains(&key.as_str()) {
                if let Some(string_value) = value.as_str() {
                    builder = builder.attribute(key.clone(), string_value.to_string());
                } else if let Ok(string_value) = serde_json::to_string(value) {
                    builder = builder.attribute(key.clone(), string_value);
                }
            }
        }

        builder
    }

    /// 从 API Key 信息创建 Principal
    pub fn from_api_key_info(
        key_id: String,
        owner: String,
        roles: Vec<String>,
        permissions: Vec<String>,
        attributes: HashMap<String, String>,
        expires_at: Option<SystemTime>,
    ) -> PrincipalBuilder {
        let mut builder = PrincipalBuilder::new(key_id.clone())
            .name(format!("API Key for {}", owner))
            .roles(roles)
            .permissions(permissions)
            .attributes(attributes)
            .attribute("owner".to_string(), owner.clone())
            .attribute("api_key_id".to_string(), key_id);

        // 确定主体类型
        if builder.roles.contains(&"admin".to_string()) {
            builder = builder.principal_type(PrincipalType::Admin);
        } else if owner.starts_with("service:") {
            builder = builder.principal_type(PrincipalType::Service);
        } else {
            builder = builder.principal_type(PrincipalType::User);
        }

        // 设置过期时间
        if let Some(expires_at) = expires_at {
            builder = builder.expires_at(expires_at);
        }

        builder
    }

    /// 从通用属性映射创建 Principal
    pub fn from_attributes(
        user_id: String,
        attributes: HashMap<String, String>,
    ) -> PrincipalBuilder {
        let mut builder = PrincipalBuilder::new(user_id);

        // 提取标准属性
        if let Some(name) = attributes.get("name") {
            builder = builder.name(name.clone());
        }

        if let Some(user_type) = attributes.get("user_type") {
            builder = builder.principal_type_from_str(user_type);
        }

        // 提取角色（假设以逗号分隔）
        if let Some(roles_str) = attributes.get("roles") {
            let roles: Vec<String> = roles_str
                .split(',')
                .map(|s| s.trim().to_string())
                .filter(|s| !s.is_empty())
                .collect();
            builder = builder.roles(roles);
        }

        // 提取权限（假设以逗号分隔）
        if let Some(permissions_str) = attributes.get("permissions") {
            let permissions: Vec<String> = permissions_str
                .split(',')
                .map(|s| s.trim().to_string())
                .filter(|s| !s.is_empty())
                .collect();
            builder = builder.permissions(permissions);
        }

        // 添加其他属性
        let reserved_keys = ["name", "user_type", "roles", "permissions"];
        for (key, value) in attributes {
            if !reserved_keys.contains(&key.as_str()) {
                builder = builder.attribute(key, value);
            }
        }

        builder
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_principal_builder() {
        let principal = PrincipalBuilder::new("user123".to_string())
            .name("John Doe".to_string())
            .principal_type(PrincipalType::User)
            .role("admin".to_string())
            .role("user".to_string())
            .permission("read:users".to_string())
            .permission("write:users".to_string())
            .attribute("department".to_string(), "Engineering".to_string())
            .expires_after(Duration::from_secs(3600))
            .build();

        assert_eq!(principal.id, "user123");
        assert_eq!(principal.name, "John Doe");
        assert!(principal.has_role("admin"));
        assert!(principal.has_role("user"));
        assert!(principal.has_permission("read:users"));
        assert!(principal.has_permission("write:users"));
        assert_eq!(principal.get_attribute("department"), Some("Engineering"));
        assert!(!principal.is_expired());
    }

    #[test]
    fn test_jwt_claims_conversion() {
        let mut claims = HashMap::new();
        claims.insert("name".to_string(), serde_json::Value::String("Jane Doe".to_string()));
        claims.insert("user_type".to_string(), serde_json::Value::String("admin".to_string()));
        claims.insert("roles".to_string(), serde_json::Value::Array(vec![
            serde_json::Value::String("admin".to_string()),
            serde_json::Value::String("user".to_string()),
        ]));
        claims.insert("permissions".to_string(), serde_json::Value::Array(vec![
            serde_json::Value::String("read:all".to_string()),
            serde_json::Value::String("write:all".to_string()),
        ]));
        claims.insert("exp".to_string(), serde_json::Value::Number(serde_json::Number::from(9999999999i64)));

        let principal = PrincipalConverter::from_jwt_claims("user456".to_string(), &claims).build();

        assert_eq!(principal.id, "user456");
        assert_eq!(principal.name, "Jane Doe");
        assert_eq!(principal.principal_type, PrincipalType::Admin);
        assert!(principal.has_role("admin"));
        assert!(principal.has_permission("read:all"));
    }

    #[test]
    fn test_api_key_conversion() {
        let principal = PrincipalConverter::from_api_key_info(
            "key123".to_string(),
            "service:payment".to_string(),
            vec!["service".to_string()],
            vec!["payment:read".to_string(), "payment:write".to_string()],
            HashMap::new(),
            None,
        ).build();

        assert_eq!(principal.id, "key123");
        assert_eq!(principal.principal_type, PrincipalType::Service);
        assert!(principal.has_role("service"));
        assert!(principal.has_permission("payment:read"));
        assert_eq!(principal.get_attribute("owner"), Some("service:payment"));
    }
}